module IPFS.Client.Command.Pin (
    PinType(..),
    PinFileList(..),
    PinFileInfo(..),
    ls,
    add,
    rm,
    RespPinInfo(..)
) where

------------------------ls------------------------------
import Prelude

import Data.Argonaut (class DecodeJson, Json, caseJsonObject, caseJsonString, decodeJson, fromString)
import Data.Argonaut.Decode ((.:))
import Data.Either (Either)
import Data.Generic.Rep (class Generic)
import Data.Generic.Rep.Show (genericShow)
import Data.Maybe (Maybe(..), fromJust, maybe)
import Data.Tuple.Nested ((/\))
import Effect.Aff (Aff)
import Foreign.Object as O
import IPFS.Client (Client)
import IPFS.Client.Command (Command, defCommand, genQSObject)
import IPFS.Client.Utils.SendRequest (execJsonCommand)
import Partial.Unsafe (unsafePartial)

------------------------ls------------------------------
data PinType = Direct | Indirect | Recursive | All
newtype PinFile = PinFile  { hash::String , pinType::PinType }

instance showPinType :: Show PinType where
 show Direct    = "direct"
 show Indirect  = "indirect"
 show Recursive = "recursive"
 show All       = "all"

readPinType::String -> PinType
readPinType "direct" = Direct
readPinType "indirect" = Indirect
readPinType "recursive" = Recursive
readPinType "all"    = All
readPinType _        = All

newtype PinFileList =  PinFileList (Array PinFileInfo)
derive instance genericPinFileList :: Generic PinFileList _
instance showPinFileList :: Show PinFileList where
  show s = genericShow s

newtype PinFileInfo = PinFileInfo {
   hash::String,
   pinType::PinType
}

derive instance genericPinFileInfo :: Generic PinFileInfo _
instance showPinFileInfo :: Show PinFileInfo where
  show s = genericShow s

instance decodeJsonPinFileList :: DecodeJson PinFileList where
  decodeJson json  = do
    djson::O.Object Json <- decodeJson json
    keys::O.Object Json <- djson .: "Keys"
    let keyArray = O.keys keys
    let pinInfoList = map (\kstr -> let hashJson = unsafePartial $ fromJust $ O.lookup kstr keys
                                        hashObj  = caseJsonObject O.empty identity hashJson
                                        typ      = caseJsonString "" identity  (unsafePartial $ fromJust $ O.lookup "Type" hashObj)
                                    in  PinFileInfo {hash:kstr,pinType:readPinType typ}
                          ) keyArray
    pure $ PinFileList pinInfoList

lsCommand::Maybe String -> Maybe PinType -> Maybe Boolean -> Command
lsCommand mayPath pinType quiet = defCommand {path = "pin/ls",
                                              args = maybe Nothing (\p -> Just [fromString p]) mayPath,
                                              qs  = genQSObject ["type"  /\ (show <$> pinType),
                                                                 "quiet" /\ (show <$> quiet) ] O.empty}

ls::Client -> Maybe String -> Maybe PinType -> Maybe Boolean -> Aff (Either String PinFileList)
ls client mayPath pinType quiet = execJsonCommand client $ lsCommand mayPath pinType quiet

------------------------add----rm--------------------------
--{"Pins":["QmUpgeg514FFEa2Hou93LQcN2YzT2py6itoKueSsyTjuQz"]}
newtype RespPinInfo = RespPinInfo (Array String)

derive instance genericRespPinInfo :: Generic RespPinInfo _
instance showRespPinInfo :: Show RespPinInfo where
  show s = genericShow s

instance decodeJsonRespPinInfo :: DecodeJson RespPinInfo where
  decodeJson json  = do
    djson::O.Object Json <- decodeJson json
    hashes::Array String <- djson .: "Pins"
    pure $ RespPinInfo hashes



addOrRmCommand::String -> String -> Maybe Boolean -> Command
addOrRmCommand apiPath path recursive  = defCommand {path = apiPath ,args = Just [fromString path] ,
                                                 qs = genQSObject ["recursive" /\ (show <$> recursive)] O.empty
                                                }

add::Client -> String -> Maybe Boolean  -> Aff (Either String RespPinInfo)
add client path recursive  = execJsonCommand client $ addOrRmCommand "pin/add" path recursive

rm::Client -> String -> Maybe Boolean  -> Aff (Either String RespPinInfo)
rm client path recursive  = execJsonCommand client $ addOrRmCommand "pin/rm" path recursive